import { Base } from "./constants";

/**
 * 解析页面标题
 * @param pageTitle
 */
export function resolveTitle (pageTitle) {
  if (!pageTitle) {
    return Base.title?.match(/^[0-9a-zA-Z\u4e00-\u9fa5]+/)?.[0] ?? ''
  }
  if (Base.title.includes('{name}')) {
    return Base.title.replace('{name}', pageTitle)
  }
  return pageTitle
}

/**
 * @description 函数防抖，闭包版
 */
export function debounce (func, wait, immediate) {
  let timeout, context, timestamp, result

  const later = function () {
    // 据上一次触发时间间隔
    const last = +new Date() - timestamp

    // 上次被包装函数被调用时间间隔last小于设定时间间隔wait
    if (last < wait && last > 0) {
      timeout = setTimeout(later, wait - last)
    } else {
      timeout = null
      // 如果设定为immediate===true，因为开始边界已经调用过了此处无需调用
      if (!immediate) {
        result = func.apply(context, arguments)
        if (!timeout) context = null
      }
    }
  }

  return function () {
    context = this
    timestamp = +new Date()
    const callNow = immediate && !timeout
    // 如果延时不存在，重新设定延时
    if (!timeout) timeout = setTimeout(later, wait)
    if (callNow) {
      result = func.apply(context, arguments)
      context = null
    }

    return result
  }
}

/**
 * 时间格式化函数
 * 月(M)、日(d)、小时(h)、分(m)、秒(s)、季度(q) 可以用 1-2 个占位符，
 * 年(y)可以用 1-4 个占位符，毫秒(S)只能用 1 个占位符(是 1-3 位的数字)
 *
 * @param {Date | number | string} date Date对象或者时间戳
 * @param {string} [fmt = 'yyyy-MM-dd hh:mm:ss'] 格式化字符串
 *        ("yyyy-MM-dd hh:mm:ss.S") ==> 2006-07-02 08:09:04.423
 *        ("yyyy-M-d h:m:s.S")      ==> 2006-7-2 8:9:4.18
 * @returns {string} 格式化后的字符串
 */
export function formatDate (date, fmt = 'yyyy-MM-dd hh:mm:ss') {
  //如果是时间戳的话那么转换成Date类型
  if (typeof date === 'string') {
    date = new Date(date)
  }

  let o = {
    //月份
    "M+": date.getMonth() + 1,
    //日
    "d+": date.getDate(),
    //小时
    "h+": date.getHours(),
    //分
    "m+": date.getMinutes(),
    //秒
    "s+": date.getSeconds(),
    //季度
    "q+": Math.floor((date.getMonth() + 3) / 3),
    //毫秒
    "S": date.getMilliseconds()
  };
  if (/(y+)/.test(fmt))
    fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length))
  for (let k in o)
    if (new RegExp("(" + k + ")").test(fmt))
      fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)))
  return fmt
}

export const fillZero = (num, len = 2) => (`0${ num }`).slice(-len)

/**
 * 时间格式化（昨天、今天、...）
 * @param {number | string | object} datetime 能被 new Date() 转换的参数
 * @returns {string} 格式化后的字符串
 */
export function timestampFormat (datetime) {
  if (typeof datetime !== 'object') {
    // 排除用户直接传入 new Date() 参数
    datetime = new Date(datetime)
  }
  const ONE_MIN = 60000 // 一分钟
  const ONE_HOUR = 3600000 // 一小时
  const ONE_DAY = 86400000 // 一天
  // 当前时间日期对象
  const curDate = new Date()
  // 当前时间戳
  const curTimestamp = curDate.getTime()
  // 参数时间戳与当前时间戳相差秒数
  const timestampDiff = curTimestamp - (+datetime)
  // 参数时间戳转换成的日期对象
  const tmDate = datetime
  const Y = tmDate.getFullYear(), m = tmDate.getMonth() + 1, d = tmDate.getDate()
  const H = tmDate.getHours(), i = tmDate.getMinutes()
  // 一分钟以内
  if (timestampDiff < ONE_MIN) return "刚刚"
  // 一小时前之内
  if (timestampDiff < ONE_HOUR) return Math.floor(timestampDiff / ONE_MIN) + "分钟前"
  // 一个小时之后，今天之内
  if (curDate.getFullYear() === Y && curDate.getMonth() + 1 === m && curDate.getDate() === d) {
    return '今天 ' + fillZero(H) + ':' + fillZero(i)
  }
  // 参数中的时间戳加一天转换成的日期对象
  const newDate = new Date(curTimestamp - ONE_DAY)
  // 昨天
  if (newDate.getFullYear() === Y && newDate.getMonth() + 1 === m && newDate.getDate() === d) {
    return '昨天 ' + fillZero(H) + ':' + fillZero(i)
  }
  // 今年
  if (curDate.getFullYear() === Y) {
    return fillZero(m) + '月' + fillZero(d) + '日 ' + fillZero(H) + ':' + fillZero(i)
  }
  // 正常格式
  return Y + '年' + fillZero(m) + '月' + fillZero(d) + '日 ' + fillZero(H) + ':' + fillZero(i)
}

/**
 * 保留小数
 * @param {number | string} number
 * @param {number} [decimal = 2]
 * @return {number}
 */
export function formatDecimal (number, decimal = 2) {
  const n = +number.toFixed(decimal)
  return isNaN(n) ? 0 : n
}
